package cn.jolyoulu.common.netty.utils;

import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 客户端管理工具类
 *
 * @Author: JolyouLu
 * @Date: 2025/9/8 11:30
 * @Version 1.0
 */
@Slf4j
public class ChannelGroupUtils {

    /**
     * 管理所有连接的ChannelGroup
     */
    private static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 标签Map
     */
    private static final ConcurrentHashMap<String, AttributeKey<Object>> TAG_MAP = new ConcurrentHashMap<>();

    /**
     * 业务id与通道id关联信息
     */
    private static final ConcurrentHashMap<String, ChannelId> KEY_CHANNEL_ID_MAP = new ConcurrentHashMap<>();

    /**
     * 添加一个客户端
     *
     * @param key 连接的唯一标识
     * @param ch  连接
     */
    public static void add(String key, Channel ch) {
        //key与通道id关联上
        KEY_CHANNEL_ID_MAP.put(key, ch.id());
        //添加到客户端组
        ALL_CHANNELS.add(ch);
    }

    /**
     * 移除一个客户端
     *
     * @param key 连接的唯一标识
     */
    public static void remove(String key) {
        Channel channel = getByKey(key);
        if (Objects.isNull(channel)) {
            return;
        }
        //关闭客户端
        channel.close();
        KEY_CHANNEL_ID_MAP.remove(key);
        ALL_CHANNELS.remove(channel);
    }

    /**
     * 根据key获取客户端
     *
     * @param key 连接的唯一标识
     * @return 客户端通道
     */
    public static Channel getByKey(String key) {
        ChannelId channelId = KEY_CHANNEL_ID_MAP.get(key);
        if (Objects.isNull(channelId)) {
            return null;
        }
        return ALL_CHANNELS.find(channelId);
    }

    /**
     * 通道id查询客户端
     *
     * @param channelId 通道Id
     * @return
     */
    public static Channel getByChannelId(ChannelId channelId) {
        return ALL_CHANNELS.find(channelId);
    }

    /**
     * 给Channel关联上标签
     *
     * @param ch       Channel
     * @param tag      标签
     * @param tagValue 标签内容
     */
    public static <T> void setTag(Channel ch, String tag, T tagValue) {
        AttributeKey<Object> attributeKey = TAG_MAP.putIfAbsent(tag, AttributeKey.newInstance(tag));
        if (Objects.isNull(attributeKey)) {
            attributeKey = TAG_MAP.get(tag);
        }
        ch.attr(attributeKey).set(tagValue);
    }

    /**
     * 获取Channel关联的标签内容
     *
     * @param ch  Channel
     * @param tag 标签
     */
    @SuppressWarnings("unchecked")
    public static <T> T getTag(Channel ch, String tag) {
        AttributeKey<Object> attributeKey = TAG_MAP.get(tag);
        if (Objects.isNull(attributeKey)) {
            return null;
        }
        try {
            //手动类型转化
            return (T) ch.attr(attributeKey).get();
        } catch (ClassCastException e) {
            log.warn("获取标签[{}]时发生类型转换错误", tag, e);
            return null;
        }
    }

    /**
     * 群发消息，给拥有指定标签内容的客户端发送消息
     * @param tag 标签
     * @param tagValue 标签值，利用equals方法比对
     * @param message 消息
     */
    public static void whiteByTag(String tag, Object tagValue, Object message) {
        AttributeKey<Object> attributeKey = TAG_MAP.get(tag);
        ALL_CHANNELS.write(message, channel -> {
            Object object = channel.attr(attributeKey).get();
            return Objects.nonNull(object) && object.equals(tagValue);
        });
    }

    /**
     * 群发消息，给拥有指定标签内容的客户端发送消息
     * @param tag 标签
     * @param tagValue 标签值，利用equals方法比对
     * @param message 消息
     */
    public static void writeAndFlushByTag(String tag, Object tagValue, Object message) {
        AttributeKey<Object> attributeKey = TAG_MAP.get(tag);
        ALL_CHANNELS.writeAndFlush(message, channel -> {
            Object object = channel.attr(attributeKey).get();
            return Objects.nonNull(object) && object.equals(tagValue);
        });
    }
}
